﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Controller;
using IAI.RP;
using Interface;

namespace IAI
{
    public partial class UCLive // This class is edited by Mads Rud Nielsen, Tien Loan Tran, Per Leth Andersen, Mads Enemark, Trang Ho
    {
        #region private attributes
        private readonly MyController _myController;
        private int _counter;
        private readonly Settings1 _settings;
        private string _emner = null,
                       _plnr = null,
                       _txt;
        private readonly BrushConverter _brushConverter = new BrushConverter();
        #endregion

        public UCLive(MyController myController)
        {
            InitializeComponent();
            _myController = myController;
            _settings = new Settings1(); // Mads Rud Nielsen
            ComboBoxEmner();
            tcContent.Focus();
        }

        #region Methods
        public Brush String2Brush(string color)
        {
            return (Brush)_brushConverter.ConvertFrom(color);
        }
        public void DataGridFeature() //Trang + Tien
        {
            dgFeature.Columns.Clear();
            var columnList = new[] //Tien - 16. maj
                { //column name, header name, width                    
                    new[] {"Name", "Navn", "120"},
                    new[] {"Nominal", "Nominal", "20"},
                    new[] {"TolPos", "Positiv Tolerance", "30"},
                    new[] {"TolNeg", "Negativ Tolerance", "40"},
                    new[] {"Measured", "Mål", "20"},
                    new[] {"Deviation", "Afvigelse", "20"},
                    new[] {"Test", "Test", "10"},
                    new[] {"NDescription", "Note","465"}
                };

            //http://stackoverflow.com/questions/11036533/datagridcolumn-binding-with-dynamically-generated-data
            int i = 0;
            foreach (string[] c in columnList)
            {
                dgFeature.Columns.Add(
                    new DataGridTextColumn { Binding = new Binding(string.Format(c[0])), Header = c[1], Width = int.Parse(c[2]) });
                i++;
            }
            IEnumerable<IFeatureMask> data = _myController.DgData(_emner, _plnr);
            //Row trigger style
            //http://social.msdn.microsoft.com/forums/en-US/wpf/thread/d5105726-52a4-4ff2-a04a-628253a9c610/
            //http://stackoverflow.com/questions/11366851/wpf-datagrid-row-foreground-in-code-behind

            dgFeature.ItemsSource = data;
            Style rowStyle = new Style { TargetType = typeof(DataGridRow) };
            DataTrigger rowTrigger = new DataTrigger { Binding = new Binding("Test"), Value = "Fail" };
            int count = data.Count(d => d.Test == "Fail"); //tæl fail
            if (count > 0)
                rowStyle.Setters.Add(new Setter(BackgroundProperty,
                                                _brushConverter.ConvertFrom(
                                                    _settings.cbPLHasFailFeatureWithoutFailColor)));
            Setter s = new Setter(BackgroundProperty,
                                  _brushConverter.ConvertFrom(_settings.cbPLHasFailFeatureWithFailColor));

            rowTrigger.Setters.Add(s);
            rowStyle.Triggers.Add(rowTrigger);
            dgFeature.RowStyle = rowStyle;
            dgFeature.Items.Refresh();
        }
        public void ComboBoxEmner()
        {
            for (int i = _myController.GetReport().Count - 1; i >= 0; i--)
                if (!cbEmner.Items.Contains(_myController.GetReport()[i].Model))
                    cbEmner.Items.Add(_myController.GetReport()[i].Model);
            cbEmner.SelectedIndex = 0;
        }
        private double LinearRegression(double[] ligning, double x)
        {
            // Linjens ligning: ax + b
            //ligning[0] = a, ligning[1] = b
            return ligning[0] * x + ligning[1];
        }
        private double[] LinearEquation(List<KeyValuePair<string, double>> valueList) // Find linjens ligning (burde kun blive kørt én gang):
        {
            int n = valueList.Count; // Antal målinger (n):
            // ∑XY, ∑X^2, ∑X samt ∑Y oprettes og sættes lig med 0:
            double sumXy = 0.0;
            double sumX2 = 0.0;
            double sumX = 0.0;
            double sumY = 0.0;
            var equation = new double[2];
            for (int y = 0; y < n; y++) // Udregn summerne:
            {
                // y = x
                double xy = y * valueList[y].Value;
                double x2 = y * y;
                sumXy += xy;
                sumX2 += x2;
                sumX += y;
                sumY += valueList[y].Value;
            }
            double a = ((n * sumXy) - (sumX * sumY)) / ((n * sumX2) - Math.Pow(sumX, 2)); // Udregn a (hældningskoefficient):
            equation[0] = a;
            double b = (sumY - (a * sumX)) / n; // Udregn b (skæring med y-aksen):
            equation[1] = b;
            return equation;
        }
        public void FeatureButton(bool prev, bool next)
        {
            btnPrevFeature.IsEnabled = prev;
            btnNextFeature.IsEnabled = next;
        }
        /// <summary>
        /// Metode der bruges til at vise graf
        /// Per Leth Andersen
        /// </summary>
        public void ShowChart(IFeatureMask selectedFeature)
        {
            graph.DataContext = null;
            if (dgFeature.SelectedIndex == 0) //set buttons
                FeatureButton(false, true);
            else if (dgFeature.SelectedIndex == dgFeature.Items.Count - 1)
                FeatureButton(true, false);
            else
                FeatureButton(true, true);

            var valueList = new List<KeyValuePair<string, double>>();
            var maxList = new List<KeyValuePair<string, double>>();
            var minList = new List<KeyValuePair<string, double>>();
            var nominal = new List<KeyValuePair<string, double>>();

            var feature =
                (_myController.GetData().Where(d => d.FbmRId.Model == _emner &&
                                                    d.FbmFId.Id == selectedFeature.Fid ||
                                                    d.FbmFId.Id == selectedFeature.Fid))
                                        .ToList();
            foreach (IFbmData t in feature)
            {
                valueList.Add(new KeyValuePair<string, double>(t.FbmRId.Serial, t.Measured));
                maxList.Add(new KeyValuePair<string, double>(t.FbmRId.Serial, t.FbmFId.Nominal + t.FbmFId.TolPos));
                minList.Add(new KeyValuePair<string, double>(t.FbmRId.Serial, t.FbmFId.Nominal + t.FbmFId.TolNeg));
                nominal.Add(new KeyValuePair<string, double>(t.FbmRId.Serial, t.FbmFId.Nominal));
            }
            var ligning = LinearEquation(valueList); // REGRESSION - Find linjens ligning (double[2]): 
            var regression =
                feature.Select((t, i) => new KeyValuePair<string, double>(t.FbmRId.Serial, LinearRegression(ligning, i)))
                       .ToList();

            var dataSourceList = new List<List<KeyValuePair<string, double>>> { valueList, maxList, minList, nominal, regression };
            graph.Title = selectedFeature.Name + " - " + selectedFeature.Model;
            graph.DataContext = dataSourceList;
            graph.UpdateLayout();
        }
        #endregion

        #region Events
        private void btnNextFeature_Click(object sender, RoutedEventArgs e)
        {
            int nextFeauture = dgFeature.SelectedIndex + 1;
            dgFeature.SelectedIndex = nextFeauture;
            if (nextFeauture < dgFeature.Items.Count)
            {
                IFeatureMask selectionGrafRow = (IFeatureMask)dgFeature.Items[nextFeauture];
                ShowChart(selectionGrafRow);
            }
        }
        private void btnPrevFeature_Click(object sender, RoutedEventArgs e)
        {
            int preFeauture = dgFeature.SelectedIndex - 1;
            dgFeature.SelectedIndex = preFeauture;
            if (preFeauture >= 0)
            {
                IFeatureMask selectionGrafRow = (IFeatureMask)dgFeature.Items[preFeauture];
                ShowChart(selectionGrafRow);
            }
        }

        #region Timer - Mads Rud Nielsen
        public void StartOnlineTimer(object o, RoutedEventArgs sender) // Online tid counter
        {
            var myDispatcherTimer = new DispatcherTimer();
            myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
            myDispatcherTimer.Tick += Each_Tick;
            myDispatcherTimer.Start();
        }
        public void Each_Tick(object o, EventArgs sender) // Online tid counter
        {
            TimeSpan t = TimeSpan.FromSeconds(_counter++);
            lblOnlineTime.Content = "Onlinetid: " + t.ToString();
        }
        public void StartUpdateTimer(object sender, RoutedEventArgs e) //Tien - 28. maj
        {
            DispatcherTimer dtUpdate = new DispatcherTimer();
            dtUpdate.Interval = new TimeSpan(0, _settings.Interval, 0);
            dtUpdate.Tick += UpdateTick;
            dtUpdate.Start();
        }
        public void UpdateTick(object o, EventArgs sender)
        {
            TimeSpan t = TimeSpan.FromMinutes(_settings.Interval);
            if (_myController.Refresh()) //is true
            {
                Console.WriteLine("true");

                cbPLNR.Items.Clear();
                _emner = cbEmner.SelectedItem.ToString();
                for (int i = _myController.GetReport().Count - 1; i >= 0; i--)
                    if (_myController.GetReport()[i].Model == _emner)
                        cbPLNR.Items.Add(_myController.GetReport()[i].Serial);
                cbPLNR.Items.Add(_myController.GetReport()[_myController.GetReport().Count - 1].Serial);

                cbPLNR.SelectedIndex = 0;

                var selection = (IFeatureMask)cbPLNR.SelectedItem;
                ShowChart(selection);
            }
            else Console.WriteLine("false\n----");
            lblLatestUpdate.Content = DateTime.Now.ToString("dddd, dd/MM-yyyy HH:mm:ss");
        }
        #endregion
        private void btnNextPLNR_Click(object sender, RoutedEventArgs e)
        {
            int nextPLNR = cbPLNR.SelectedIndex + 1;
            int nextEmne = cbEmner.SelectedIndex + 1;

            if (nextPLNR <= cbPLNR.Items.Count)
            {
                cbPLNR.SelectedIndex = nextPLNR;
                if (nextPLNR == cbPLNR.Items.Count)
                    cbEmner.SelectedIndex = nextEmne;
            }
        }
        private void btnPrevPLNR_Click(object sender, RoutedEventArgs e)
        {
            int prevPLNR = cbPLNR.SelectedIndex - 1;
            int prevEmne = cbEmner.SelectedIndex - 1;

            if (prevPLNR > -1)
                cbPLNR.SelectedIndex = prevPLNR;
            else if (prevPLNR == -1 && prevEmne > -1)
            {
                cbEmner.SelectedIndex = prevEmne;
                cbPLNR.SelectedIndex = cbPLNR.Items.Count - 1;
            }
        }
        private void btnReport_Click(object sender, RoutedEventArgs e)
        {
            if (_emner == null)
            {
                cbEmner.SelectedIndex = 0;
                _emner = cbEmner.SelectedItem.ToString();
                _myController.Emne = _emner;
            }

            if (_plnr == null)
            {
                cbPLNR.SelectedIndex = 0;
                _plnr = cbPLNR.SelectedItem.ToString();
                _myController.PLNR = _plnr;
            }
            _myController.FMask = _myController.DgData(_emner, _plnr);
            PrintPreview pr = new PrintPreview(_myController);
            pr.ShowDialog();
            pr.Close();
        }
        private void btnUpdateData_Click(object sender, RoutedEventArgs e)
        {
            if (_myController.Refresh())
            {
                Console.WriteLine("true\n");

                cbPLNR.Items.Clear();
                _emner = cbEmner.SelectedItem.ToString();
                for (int i = _myController.GetReport().Count - 1; i >= 0; i--)
                    if (_myController.GetReport()[i].Model == _emner)
                        cbPLNR.Items.Add(_myController.GetReport()[i].Serial);
                cbPLNR.Items.Add(_myController.GetReport()[_myController.GetReport().Count - 1].Serial);

                cbPLNR.SelectedIndex = 0;

                var selectedFeature = (IFeatureMask)dgFeature.SelectedItem;
                ShowChart(selectedFeature);
            }
            else
                Console.WriteLine("false\n");
            lblLatestUpdate.Content = DateTime.Now.ToString("dddd, dd/MM-yyyy HH:mm:ss");
        }
        private void cbEmner_SelectionChanged(object sender, SelectionChangedEventArgs e) // Mads Rud Nielsen
        {
            cbPLNR.Items.Clear();
            _emner = cbEmner.SelectedItem.ToString();
            _myController.Emne = _emner;
            for (int i = _myController.GetReport().Count - 1; i >= 0; i--)
                if (_myController.GetReport()[i].Model == _emner)
                    cbPLNR.Items.Add(_myController.GetReport()[i].Serial);
            cbPLNR.SelectedIndex = 0;
        }
        private void cbPLNR_SelectionChanged(object sender, SelectionChangedEventArgs e) //Mads Enemark
        {
            if (cbPLNR.Items.Count > 0)
            {
                _plnr = cbPLNR.SelectedItem.ToString();
                _myController.PLNR = _plnr;
                dgFeature.Columns.Clear();
                DataGridFeature();
            }
            // tilstandstyring frem og tilbage knapper
            int indexPLNR = cbPLNR.SelectedIndex;
            int indexEmne = cbEmner.SelectedIndex;

            if (indexEmne == 0 && indexPLNR == 0)
                btnPrevPLNR.IsEnabled = false;
            else if ((indexEmne == cbEmner.Items.Count - 1) && (indexPLNR == cbPLNR.Items.Count - 1))
                btnNextPLNR.IsEnabled = false;
            else
            {
                btnPrevPLNR.IsEnabled = true;
                btnNextPLNR.IsEnabled = true;
            }
        }
        private void dgFeature_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            tiGraph.IsEnabled = true;
            Login l = (Login)Window.GetWindow(this);
            l.menuEditChart.IsEnabled = true;
            if (dgFeature.SelectedIndex == -1)
                dgFeature.SelectedIndex = 0;
            _myController.CurrentFeatureMask = (IFeatureMask)dgFeature.SelectedItem;
            dgFeature.SelectedItem = _myController.CurrentFeatureMask;
        }
        private void dgFeature_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.G && dgFeature.SelectedIndex != -1)
            {
                ShowChart((IFeatureMask)dgFeature.SelectedItem);
                tiGraph.IsSelected = true;
            }
        }
        private void dgFeature_MouseDoubleClick(object sender, MouseButtonEventArgs e) //Trang
        {
            if (dgFeature.Items.Count > 0)
            {
                IFeatureMask selectedRow = (IFeatureMask)dgFeature.SelectedItem;
                int selectedindex = dgFeature.SelectedIndex;
                double oldValue = selectedRow.Measured;
                int did = selectedRow.Did;

                NoteWindow noteWindow = new NoteWindow(_myController);
                noteWindow.Title = "PL: " + _plnr + ", feature: " + selectedRow.Name + " (Segment: " + _emner + ")";
                noteWindow.lblPLNumber.Content = _plnr;
                noteWindow.lblSegmentName.Content = _emner;
                noteWindow.lblFeatureName.Content = selectedRow.Name;
                noteWindow.txtOldValue.Text = oldValue.ToString();
                noteWindow.ShowDialog();
                double newValue;
                string nDescription = noteWindow.txtNDescription.Text;

                if (!noteWindow.isClose)
                {

                    double deviation;
                    bool test;
                    if (_myController.FindNote(did))
                    {
                        if (noteWindow.txtNewValue.Text == string.Empty)
                        {
                            newValue = oldValue;
                            deviation = Math.Round(newValue - selectedRow.Nominal, 1);
                            test = (deviation >= selectedRow.TolNeg && deviation <= selectedRow.TolPos);
                            _myController.UpdateNote(did, newValue, nDescription, DateTime.Now,
                                                     _myController.CurrentOperator.Initials);
                            _myController.UpdateData(did, newValue, deviation, test);
                            DataGridFeature();
                            dgFeature.SelectedIndex = selectedindex;
                        }
                        else
                        {
                            newValue = double.Parse(noteWindow.txtNewValue.Text);
                            deviation = Math.Round(newValue - selectedRow.Nominal, 1);
                            test = (deviation >= selectedRow.TolNeg && deviation <= selectedRow.TolPos);
                            _myController.UpdateNote(did, newValue, nDescription, DateTime.Now,
                                                     _myController.CurrentOperator.Initials);
                            _myController.UpdateData(did, newValue, deviation, test);
                            DataGridFeature();
                            dgFeature.SelectedIndex = selectedindex;
                        }
                    }
                    else
                    {
                        try
                        {
                            newValue = double.Parse(noteWindow.txtNewValue.Text);
                            deviation = Math.Round(newValue - selectedRow.Nominal, 1);
                            test = (deviation >= selectedRow.TolNeg && deviation <= selectedRow.TolPos);
                            _myController.AddNote2DB(did, newValue, oldValue, nDescription,
                                                     DateTime.Now, _myController.CurrentOperator.Initials);
                            _myController.AddNote(did, newValue, oldValue, nDescription, DateTime.Now,
                                                  _myController.CurrentOperator);
                            _myController.UpdateData(did, newValue, deviation, test);
                            DataGridFeature();
                            dgFeature.SelectedIndex = selectedindex;
                        }
                        catch (Exception ex) { MessageBox.Show(ex.Message); }
                    }
                }
            }
        }
        private void tiGraph_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (dgFeature.SelectedItem != null)
                ShowChart((IFeatureMask)dgFeature.SelectedItem);
        }
        private void TextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            TextBox tempTxt = (TextBox)e.Source;
            _txt = tempTxt.Text;
            if (tempTxt.Text == "Søg")
                tempTxt.Clear();
        }
        private void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            TextBox tempTxt = (TextBox)e.Source;
            if (tempTxt.Text == string.Empty || tempTxt.Text.Length == 0)
                tempTxt.Text = Equals(tempTxt, txtSearch) ? "Søg" : _txt;
        }
        private void txtSearch_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                var result = _myController.FoundItems(txtSearch.Text);
                if (result.Count != 0)
                {
                    dgFeature.ItemsSource = null;
                    if (dgFeature.Columns.Count == 8) // If the columnList has 8 elements, it's because segment isn't added - Only add it once!
                        dgFeature.Columns.Add(new DataGridTextColumn
                            {
                                Binding = new Binding("Model"),
                                Header = "Segment"
                            });
                    dgFeature.ItemsSource = result;
                }
                else
                    MessageBox.Show("Feature du søgte efter kunne ikke findes.");
            }
        }
        public void UCLive_OnKeyDown(object sender, KeyEventArgs e) // Hotkeys
        {
            if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.L))
                tiList.IsSelected = true;
            else if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.I))
            {
                Settings s = new Settings(_myController);
                s.Owner = Window.GetWindow(this);
                s.ShowDialog();
            }
            else if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.G))
            {
                if (dgFeature.SelectedIndex > -1)
                    tiGraph.IsSelected = true;
            }
            else if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.F))
                txtSearch.Focus();
            else if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.E))
            {
                if (tiGraph.IsSelected)
                    btnExport.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
                if (tiList.IsSelected)
                    btnReport.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
            }

            //Hotkey window
            if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.T))
            {
                Keys k = new Keys();
                k.ShowDialog();
            }

            // Update data
            if (Keyboard.IsKeyDown(Key.F5) || ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.R)))
                btnUpdateData.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));

            // Paging
            if (Keyboard.IsKeyDown(Key.Left))
                btnPrevPLNR.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
            else if (Keyboard.IsKeyDown(Key.Right))
                btnNextPLNR.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
        }
        private void tiList_GotFocus(object sender, RoutedEventArgs e)
        {
            if (dgFeature.SelectedIndex == -1)
            {
                if (dgFeature.Items.Count > 0)
                {
                    for (int i = 0; i < dgFeature.Items.Count; i++)
                    {
                        if (dgFeature.Items[i] == _myController.CurrentFeatureMask)
                        {
                            dgFeature.SelectedIndex = i;
                            break;
                        }
                        else
                            dgFeature.SelectedIndex = 0;
                    }
                }
            }
        }
        #endregion

        #region Gem billede af grafen
        // http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4777497c-8c97-4b54-9f42-4729898cbbe2/
        private void btnExport_Click(object sender, RoutedEventArgs e)
        {
            // Hide buttons for cleaner image <3
            btnPrevFeature.Visibility = Visibility.Hidden;
            btnNextFeature.Visibility = Visibility.Hidden;
            btnExport.Visibility = Visibility.Hidden;
            IFeatureMask selectedRow = (IFeatureMask)dgFeature.SelectedItem;
            string fileName = selectedRow.Model + "_" + selectedRow.Serial + "_" + selectedRow.Name;
            SaveUsingEncoder(fileName + ".png", graphGrid, new PngBitmapEncoder());
            // Show buttons again
            btnPrevFeature.Visibility = Visibility.Visible;
            btnNextFeature.Visibility = Visibility.Visible;
            btnExport.Visibility = Visibility.Visible;
        }
        private static void SaveUsingEncoder(string fileName, FrameworkElement UIElement, BitmapEncoder encoder)
        {
            int height = (int)UIElement.ActualHeight;
            int width = (int)UIElement.ActualWidth;
            // These two line of code make sure that you get completed visual bitmap.
            // In case your Framework Element is inside the scroll viewer then some part which is not
            // visible gets clip.  
            UIElement.Measure(new System.Windows.Size(width, height));
            UIElement.Arrange(new Rect(0, 0, width, height));
            RenderTargetBitmap bitmap = new RenderTargetBitmap(width, height, 96, 96, // These decides the dpi factors 
                // The can be changed when we'll have preview options.
                                                               PixelFormats.Pbgra32);
            bitmap.Render(UIElement);
            SaveUsingBitmapTargetRenderer(fileName, bitmap, encoder);
        }
        private static void SaveUsingBitmapTargetRenderer(string fileName, RenderTargetBitmap renderTargetBitmap,
                                                          BitmapEncoder bitmapEncoder)
        {
            BitmapFrame frame = BitmapFrame.Create(renderTargetBitmap);
            bitmapEncoder.Frames.Add(frame);
            string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); // Path to desktop
            using (var stream = File.Create(path + "/" + fileName)) // Save file .
            {
                bitmapEncoder.Save(stream);
                MessageBox.Show("Grafen blev gemt på skrivebordet");
            }
        }
        private void dgFeature_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Left || e.Key == Key.Right)
                e.Handled = true;
        }
        #endregion
    }
}
